from typing import List, Optional
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_
import logging
import uuid
import json
from datetime import datetime

from app.models.database import Task
from app.models.schemas import TaskConfig, TaskInfo, TaskStatus, TaskListParams, PaginatedResponse
from app.services.crawl_service import CrawlService, MockCrawlService
from app.config import settings

logger = logging.getLogger(__name__)

class TaskService:
    """任务服务 - 处理任务相关的业务逻辑"""
    
    def __init__(self, crawl_service: Optional[CrawlService] = None):
        # 在开发环境使用模拟服务，生产环境使用真实服务
        if crawl_service:
            self.crawl_service = crawl_service
        elif settings.DEBUG:
            self.crawl_service = MockCrawlService()
        else:
            self.crawl_service = CrawlService()
    
    async def create_task(
        self, 
        config: TaskConfig, 
        user_id: str, 
        db: AsyncSession
    ) -> TaskInfo:
        """创建新任务"""
        try:
            # 创建任务实例
            task = Task(
                id=str(uuid.uuid4()),
                name=config.name,
                description=config.description,
                config=config.dict(),
                user_id=user_id,
                status=TaskStatus.PENDING
            )
            
            db.add(task)
            await db.commit()
            await db.refresh(task)
            
            logger.info(f"Task created: {task.id} by user {user_id}")
            
            return self._task_to_info(task)
            
        except Exception as e:
            await db.rollback()
            logger.error(f"Failed to create task: {e}")
            raise
    
    async def get_task(self, task_id: str, db: AsyncSession) -> Optional[TaskInfo]:
        """获取任务详情"""
        stmt = select(Task).where(Task.id == task_id, Task.is_active == True)
        result = await db.execute(stmt)
        task = result.scalar_one_or_none()
        
        if not task:
            return None
            
        return self._task_to_info(task)
    
    async def list_tasks(
        self, 
        params: TaskListParams, 
        user_id: str, 
        db: AsyncSession
    ) -> PaginatedResponse:
        """获取任务列表"""
        # 构建查询条件
        conditions = [Task.is_active == True, Task.user_id == user_id]
        
        if params.status:
            conditions.append(Task.status == params.status)
        
        if params.search:
            search_term = f"%{params.search}%"
            conditions.append(
                or_(
                    Task.name.ilike(search_term),
                    Task.description.ilike(search_term)
                )
            )
        
        if params.created_after:
            conditions.append(Task.created_at >= params.created_after)
        
        if params.created_before:
            conditions.append(Task.created_at <= params.created_before)
        
        # 查询总数
        count_stmt = select(func.count(Task.id)).where(and_(*conditions))
        total_result = await db.execute(count_stmt)
        total = total_result.scalar()
        
        # 查询数据
        offset = (params.page - 1) * params.size
        stmt = (
            select(Task)
            .where(and_(*conditions))
            .order_by(Task.created_at.desc())
            .offset(offset)
            .limit(params.size)
        )
        
        result = await db.execute(stmt)
        tasks = result.scalars().all()
        
        # 转换为响应格式
        items = [self._task_to_info(task) for task in tasks]
        pages = (total + params.size - 1) // params.size
        
        return PaginatedResponse(
            items=items,
            total=total,
            page=params.page,
            size=params.size,
            pages=pages
        )
    
    async def update_task(
        self, 
        task_id: str, 
        config: TaskConfig, 
        user_id: str, 
        db: AsyncSession
    ) -> Optional[TaskInfo]:
        """更新任务"""
        try:
            # 检查任务是否存在且属于当前用户
            task = await self._get_user_task(task_id, user_id, db)
            if not task:
                return None
            
            # 更新任务配置
            stmt = (
                update(Task)
                .where(Task.id == task_id, Task.user_id == user_id)
                .values(
                    name=config.name,
                    description=config.description,
                    config=config.dict(),
                    updated_at=func.now()
                )
            )
            
            await db.execute(stmt)
            await db.commit()
            
            # 返回更新后的任务
            return await self.get_task(task_id, db)
            
        except Exception as e:
            await db.rollback()
            logger.error(f"Failed to update task {task_id}: {e}")
            raise
    
    async def delete_task(
        self, 
        task_id: str, 
        user_id: str, 
        db: AsyncSession
    ) -> bool:
        """删除任务（软删除）"""
        try:
            # 检查任务是否存在且属于当前用户
            task = await self._get_user_task(task_id, user_id, db)
            if not task:
                return False
            
            # 如果任务正在运行，先停止
            if task.status == TaskStatus.RUNNING:
                await self.stop_task(task_id, user_id, db)
            
            # 软删除任务
            stmt = (
                update(Task)
                .where(Task.id == task_id, Task.user_id == user_id)
                .values(is_active=False, updated_at=func.now())
            )
            
            await db.execute(stmt)
            await db.commit()
            
            logger.info(f"Task deleted: {task_id} by user {user_id}")
            return True
            
        except Exception as e:
            await db.rollback()
            logger.error(f"Failed to delete task {task_id}: {e}")
            raise
    
    async def start_task(
        self, 
        task_id: str, 
        user_id: str, 
        db: AsyncSession
    ) -> bool:
        """启动任务"""
        try:
            task = await self._get_user_task(task_id, user_id, db)
            if not task:
                return False
            
            if task.status == TaskStatus.RUNNING:
                return True  # 已经在运行
            
            # 更新任务状态
            await self._update_task_status(task_id, TaskStatus.RUNNING, db)
            
            # 调用爬虫服务启动任务
            success = await self.crawl_service.start_crawl(task_id, task.config)
            
            if not success:
                await self._update_task_status(task_id, TaskStatus.FAILED, db)
                return False
            
            logger.info(f"Task started: {task_id}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to start task {task_id}: {e}")
            await self._update_task_status(task_id, TaskStatus.FAILED, db)
            raise
    
    async def stop_task(
        self, 
        task_id: str, 
        user_id: str, 
        db: AsyncSession
    ) -> bool:
        """停止任务"""
        try:
            task = await self._get_user_task(task_id, user_id, db)
            if not task:
                return False
            
            if task.status != TaskStatus.RUNNING:
                return True  # 不在运行状态
            
            # 调用爬虫服务停止任务
            success = await self.crawl_service.stop_crawl(task_id)
            
            if success:
                await self._update_task_status(task_id, TaskStatus.CANCELLED, db)
                logger.info(f"Task stopped: {task_id}")
            
            return success
            
        except Exception as e:
            logger.error(f"Failed to stop task {task_id}: {e}")
            raise
    
    async def get_task_status(self, task_id: str, user_id: str, db: AsyncSession) -> Optional[dict]:
        """获取任务状态"""
        try:
            task = await self._get_user_task(task_id, user_id, db)
            if not task:
                return None
            
            # 从爬虫服务获取实时状态
            crawl_status = await self.crawl_service.get_task_status(task_id)
            
            if crawl_status:
                # 更新数据库中的状态
                if crawl_status.get("status") != task.status:
                    await self._update_task_status(task_id, crawl_status.get("status"), db)
                
                return {
                    "id": task_id,
                    "status": crawl_status.get("status", task.status),
                    "progress": crawl_status.get("progress", task.progress),
                    "pages_crawled": crawl_status.get("pages_crawled", task.pages_crawled),
                    "current_url": crawl_status.get("current_url"),
                    "estimated_completion": crawl_status.get("estimated_completion")
                }
            else:
                return {
                    "id": task_id,
                    "status": task.status,
                    "progress": task.progress,
                    "pages_crawled": task.pages_crawled,
                    "current_url": None,
                    "estimated_completion": None
                }
                
        except Exception as e:
            logger.error(f"Failed to get task status {task_id}: {e}")
            return None
    
    async def _get_user_task(
        self, 
        task_id: str, 
        user_id: str, 
        db: AsyncSession
    ) -> Optional[Task]:
        """获取用户的任务"""
        stmt = select(Task).where(
            Task.id == task_id, 
            Task.user_id == user_id, 
            Task.is_active == True
        )
        result = await db.execute(stmt)
        return result.scalar_one_or_none()
    
    async def _update_task_status(
        self, 
        task_id: str, 
        status: TaskStatus, 
        db: AsyncSession
    ):
        """更新任务状态"""
        stmt = (
            update(Task)
            .where(Task.id == task_id)
            .values(status=status, updated_at=func.now())
        )
        await db.execute(stmt)
        await db.commit()
    
    def _task_to_info(self, task: Task) -> TaskInfo:
        """将数据库模型转换为响应模型"""
        return TaskInfo(
            id=task.id,
            config=TaskConfig(**task.config),
            status=TaskStatus(task.status),
            created_at=task.created_at,
            updated_at=task.updated_at,
            started_at=task.started_at,
            completed_at=task.completed_at,
            progress=task.progress,
            pages_crawled=task.pages_crawled,
            data_extracted=task.data_extracted,
            errors_count=task.errors_count,
            success_rate=task.success_rate,
            user_id=task.user_id
        )
